package dailyBlock

import (
	"math/rand"

	"gitee.com/wchpub/dwSvrPub"
	"gitee.com/wchpub/dwSvrPub/dwProto"
	"gitee.com/wchpub/dwSvrPub/sData"
	"gitee.com/wchpub/fnsvr"
	"gitee.com/wchpub/fnsvr/funcSless"
	"github.com/samber/lo"
)

type BlockType string

const (
	//数据块名称
	BlockName string = "daily"
)

const (
	//每日免费游戏次数 v2已废弃
	MAX_FREE_GAME_TIMES int = 3

	//每日大师关卡入场券数量
	//MAX_FREE_MASTER_TIMES int = 1
)

// 每日刷新的数据

const (
	//档案版本号
	Key_Ver BlockType = funcSless.GAME_DATA_VERSION_KEY

	Key_RefreshTime  BlockType = "refreshTime"  //数据刷新时间
	Key_Ticket       BlockType = "ticket"       //每日关卡入场券数量 v2已废弃
	Key_MasterTicket BlockType = "masterTicket" //每日大师关卡入场券数量

	Key_MaxFreeGameTimes BlockType = "maxFreeGameTimes" //本日最多可免费玩的次数 v2已废弃
	Key_PassTimes        BlockType = "passTimes"        //本日通关次数 在v2版本中已废弃

	Key_GameTimes     BlockType = "gameTimes"     //本日游戏次数
	Key_PassReward    BlockType = "passReward"    //今日通关奖励 1-12 在v2版本中已废弃
	Key_EditInfoTimes BlockType = "editInfoTimes" //今日编辑信息次数

)

type Data struct {
	super *funcSless.Block[BlockType]
}

// 数据刷新时间
func (m *Data) RefreshTime() (int64, error) {
	return m.super.GetInt64(Key_RefreshTime)
}

type IAutoRefreshFuncs interface {
	SetSkins(v []*dwProto.SkinInfo) error
	Skins() ([]*dwProto.SkinInfo, error)
}

// 点亮皮肤
func LightUpSkin(themeId int, funcs IAutoRefreshFuncs) (reInfo *dwProto.SkinInfo, err error) {

	skins, err := funcs.Skins()
	if err != nil {
		return nil, err
	}

	//themeId := pub.ThemeIdByTimestamp(now)
	//找到和当前主题相关的所有皮肤
	themeSkins := lo.Filter(skins, func(s *dwProto.SkinInfo, _ int) bool {
		return int(s.Id) == themeId
	})

	canLightIdxs := []int{} //可点亮队列

	//皮肤数据按照idx索引
	skinsIdxById := make(map[int]*dwProto.SkinInfo)
	for _, skin := range themeSkins {
		skinsIdxById[int(skin.Idx)] = skin
	}

	for skinIdx := 1; skinIdx <= int(dwSvrPub.MAX_BALLNO); skinIdx++ {
		_, ok := skinsIdxById[skinIdx]
		if !ok {
			canLightIdxs = append(canLightIdxs, skinIdx)
		}
	}

	//从可点亮队列随机一个
	if len(canLightIdxs) > 0 {
		r := rand.New(rand.NewSource(fnsvr.GetMilliTimestamp()))

		_idx := r.Intn(len(canLightIdxs))
		ballNo := int32(canLightIdxs[_idx])
		newSkin := &dwProto.SkinInfo{
			Id:    int32(themeId),
			Idx:   ballNo,
			State: dwProto.CollectedState_Light,
			Date:  dwSvrPub.WorldTime(),
		}
		//lightSkins = append(lightSkins, newSkin)
		skins = append(skins, newSkin)

		err = funcs.SetSkins(skins)
		if err != nil {
			return nil, err
		}

		return newSkin, nil
	}

	return nil, nil
}

// 自动刷新数据 v2已废弃
func (m *Data) AutoRefreshV2(now int64) error {

	m.super.PreLoad(Key_RefreshTime)

	refreshTime, err := m.RefreshTime()
	if err != nil {
		return err
	}

	if refreshTime != 0 && fnsvr.IsSameDay(dwSvrPub.Location, refreshTime, now) {
		return nil
	}

	if now < refreshTime {
		return nil
	}

	m.crossDayReset(now)

	return nil
}

func (m *Data) crossDayReset(now int64) {
	m.super.SetInt64(Key_RefreshTime, now)
	m.super.SetInt(Key_MaxFreeGameTimes, MAX_FREE_GAME_TIMES)
	m.SetTicket(MAX_FREE_GAME_TIMES)
	m.SetMasterTicket(int(sData.Consts_dailyMasterCoins))
	m.SetPassTimes(0)
	m.SetGameTimes(0)
	m.SetEditInfoTimes(0)
}

// 自动刷新数据 v2已废弃
func (m *Data) AutoRefresh(now int64, themeId int, funcs IAutoRefreshFuncs) error {

	//themeId := pub.ThemeIdByTimestamp(now)

	m.super.PreLoad(Key_RefreshTime)

	refreshTime, err := m.RefreshTime()
	if err != nil {
		return err
	}

	if refreshTime != 0 && fnsvr.IsSameDay(dwSvrPub.Location, refreshTime, now) {
		return nil
	}

	if now < refreshTime {
		return nil
	}

	skins, err := funcs.Skins()
	if err != nil {
		return err
	}

	m.crossDayReset(now)

	//找到和当前主题相关的所有皮肤
	themeSkins := lo.Filter(skins, func(s *dwProto.SkinInfo, _ int) bool {
		return int(s.Id) == themeId
	})

	//找到点亮的所有皮肤
	lightSkins := lo.Filter(themeSkins, func(s *dwProto.SkinInfo, _ int) bool {
		return s.State == dwProto.CollectedState_Light
	})

	r := rand.New(rand.NewSource(fnsvr.GetMilliTimestamp()))

	if len(lightSkins) == 0 {
		//自动点亮皮肤
		newSkin, err := LightUpSkin(themeId, funcs)
		if err != nil {
			return err
		}
		if newSkin != nil {
			lightSkins = append(lightSkins, newSkin)
		}

	}

	if len(lightSkins) == 0 {
		//全部已经获取了

		m.SetPassReward(r.Intn(int(dwSvrPub.MAX_BALLNO)) + 1)
	} else {
		//从已点亮皮肤中随机一个

		m.SetPassReward(int(lightSkins[r.Intn(len(lightSkins))].Idx))

	}

	return nil
}

// 通关次数
func (m *Data) PassTimes() (int, error) {
	return m.super.GetInt(Key_PassTimes)
}

func (m *Data) SetPassTimes(v int) {
	m.super.SetInt(Key_PassTimes, v)
}

// 游戏次数
func (m *Data) GameTimes() (int, error) {
	return m.super.GetInt(Key_GameTimes)
}

func (m *Data) SetGameTimes(v int) {
	m.super.SetInt(Key_GameTimes, v)
}

// 日常关卡入场券数量
func (m *Data) Ticket() (int, error) {
	return m.super.GetInt(Key_Ticket)
}

func (m *Data) SetTicket(v int) {
	m.super.SetInt(Key_Ticket, v)
}

// 大师关卡入场券数量
func (m *Data) MasterTicket() (int, error) {
	return m.super.GetInt(Key_MasterTicket)
}

func (m *Data) SetMasterTicket(v int) {
	m.super.SetInt(Key_MasterTicket, v)
}

// 今日通关奖励
func (m *Data) PassReward() (int, error) {
	return m.super.GetInt(Key_PassReward)
}

func (m *Data) SetPassReward(v int) {
	m.super.SetInt(Key_PassReward, v)
}

// 今日编辑信息次数
func (m *Data) EditInfoTimes() (int, error) {
	return m.super.GetInt(Key_EditInfoTimes)
}

func (m *Data) SetEditInfoTimes(v int) {
	m.super.SetInt(Key_EditInfoTimes, v)
}

/*
// 通关奖励候选列表
func (m *Data) RewardList() ([]int, error) {
	re := []int{}
	err := m.super.GetJson(Key_RewardList, &re)
	if err != nil {
		return nil, err
	}

	return re, nil
}

func (m *Data) SetRewardList(v []int) {
	err := m.super.SetJson(Key_RewardList, v)
	if err != nil {
		fnsvr.Log().Error("dailyBlock.SetRewardList", "v", v, "err", err)
	}
}*/

func (m *Data) PreLoad(keys ...BlockType) {
	m.super.PreLoad(keys...)
}

func (m *Data) GetAll() (map[string]string, error) {
	return m.super.GetAll()
}

func (m *Data) GetString(key string) (string, error) {
	return m.super.GetString(BlockType(key))
}

func (m *Data) BlockName() string {
	return BlockName
}

// 获取数据块
func GetBlock(plyData *funcSless.PlayerData) (*Data, error) {

	bk, err := funcSless.GetBlock[BlockType](plyData, BlockName)
	if err != nil {
		return nil, err
	}

	return &Data{
		super: bk,
	}, nil
}
